#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Author : iflytek
import requests
import json
import base64
import hashlib
import time
from urllib.parse import urlencode
import hmac
from datetime import datetime
from wsgiref.handlers import format_date_time
from time import mktime
import sys
import os

num=1

class TestTask():

    def __init__(self):
        HOST = "api-dx.xf-yun.com"
        APP_ID = "8f1cd5b1"
        API_KEY = "cdf5117b7956d78a9d5d4b8d73fd8a30"
        API_SECRET = "OWIxYzBhZGQyYmFjNDA3MjllOWNjMDU4"
        self.host = HOST
        self.app_id = APP_ID
        self.api_key = API_KEY
        self.api_secret = API_SECRET

    # 生成鉴权的url
    def assemble_auth_url(self, path):
        params = self.assemble_auth_params(path)
        # 请求地址
        request_url = "http://" + self.host + path
        # 拼接请求地址和鉴权参数，生成带鉴权参数的url
        auth_url = request_url + "?" + urlencode(params)
        return auth_url

    # 生成鉴权的参数
    def assemble_auth_params(self, path):
        # 生成RFC1123格式的时间戳
        format_date = format_date_time(mktime(datetime.now().timetuple()))
        # 拼接字符串
        signature_origin = "host: " + self.host + "\n"
        signature_origin += "date: " + format_date + "\n"
        signature_origin += "POST " + path + " HTTP/1.1"
        # 进行hmac-sha256加密
        signature_sha = hmac.new(self.api_secret.encode('utf-8'), signature_origin.encode('utf-8'),
                                 digestmod=hashlib.sha256).digest()
        signature_sha = base64.b64encode(signature_sha).decode(encoding='utf-8')
        # 构建请求参数
        authorization_origin = 'api_key="%s", algorithm="%s", headers="%s", signature="%s"' % (
            self.api_key, "hmac-sha256", "host date request-line", signature_sha)
        # 将请求参数使用base64编码
        authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8')
        # 将请求的鉴权参数组合为字典
        params = {
            "host": self.host,
            "date": format_date,
            "authorization": authorization
        }
        return params

    # 创建任务
    def test_create(self, text):
        # 创建任务的路由
        create_path = "/v1/private/dts_create"
        # 拼接鉴权参数后生成的url
        auth_url = self.assemble_auth_url(create_path)
        # 合成文本
        encode_str = base64.encodebytes(text.encode("UTF8"))
        txt = encode_str.decode()
        # 请求头
        headers = {'Content-Type': 'application/json'}
        # 请求参数，字段具体含义见官网文档：https://aidocs.xfyun.cn/docs/dts/%E6%8E%A5%E5%8F%A3%E5%8D%8F%E8%AE%AEv3.html
        data = {
            "header": {
                "app_id": self.app_id,
                # "callback_url": "",
                # "request_id": ""
            },
            "parameter": {
                "dts": {
                    "vcn": "x4_xiaozhong",#请先在控制台开通发音人权限
                    "language": "zh",
                    "speed": 50,
                    "volume": 50,
                    "pitch": 50,
                    "rhy": 1,
                    "bgs": 0,
                    "reg": 0,
                    "rdn": 0,
                    "scn": 0,
                    "audio": {
                        "encoding": "lame", # 下方下载的文件后缀需要保持一致
                        "sample_rate": 16000,
                        "channels": 1,
                        "bit_depth": 16,
                        "frame_size": 0
                    },
                    "pybuf": {
                        "encoding": "utf8",
                        "compress": "raw",
                        "format": "plain"
                    }
                }
            },
            "payload": {
                "text": {
                    "encoding": "utf8",
                    "compress": "raw",
                    "format": "plain",
                    "text": txt
                }
            },
        }
        try:
            print("创建任务请求参数:", json.dumps(data))
            res = requests.post(url=auth_url, headers=headers, data=json.dumps(data))
            res = json.loads(res.text)
            return res
        except Exception as e:
            print("创建任务接口调用异常，错误详情:%s" % e)
            sys.exit(1)

    # 查询任务
    def test_query(self, task_id):
        # 查询任务的路由
        query_path = "/v1/private/dts_query"
        # 拼接鉴权参数后生成的url
        auth_url = self.assemble_auth_url(query_path)
        # 请求头
        headers = {'Content-Type': 'application/json'}
        # 请求参数，字段具体含义见官网文档：https://aidocs.xfyun.cn/docs/dts/%E6%8E%A5%E5%8F%A3%E5%8D%8F%E8%AE%AEv3.html
        data = {
            "header": {
                "app_id": self.app_id,
                "task_id": task_id
            }
        }
        try:
            print("\n查询任务请求参数:",json.dumps(data))
            res = requests.post(url=auth_url, headers=headers, data=json.dumps(data))
            res = json.loads(res.text)
            return res
        except Exception as e:
            print("查询任务接口调用异常，错误详情:%s" % e)
            sys.exit(1)


# 创建任务
def do_create(text):
    # 调用创建任务接口
    test_task = TestTask()
    create_result = test_task.test_create(text)
    print("create_response:",json.dumps(create_result))
    # 创建任务接口返回状态码
    code = create_result.get('header', {}).get('code')
    # 状态码为0，创建任务成功，打印task_id, 用于后续查询任务
    if code == 0:
        task_id = create_result.get('header', {}).get('task_id')
        print("创建任务成功，task_id: %s" % task_id)
        return task_id
    # 状态码非0，创建任务失败, 相关错误码参考官网文档：https://aidocs.xfyun.cn/docs/dts/%E6%8E%A5%E5%8F%A3%E5%8D%8F%E8%AE%AEv3.html
    else:
        print("创建任务失败，返回状态码: %s" % code)

# 查询任务
def do_query(task_id):
    test_task = TestTask()
    # 这里循环调用查询结果，当task_status状态为'5'（即大文本合成任务完成）时停止循环，循环次数和sleep时间可酌情定义
    try:
        for i in range(9):
            # 等待1秒
            time.sleep(1)
            # 调用查询任务接口
            query_result = test_task.test_query(task_id)
            print("query_response:",json.dumps(query_result))
            # 查询任务接口返回状态码
            code = query_result.get('header', {}).get('code')
            # 状态码为0，查询任务成功
            if code == 0:
                # 任务状态码：1-任务创建成功 2-任务派发失败 4-结果处理中 5-结果处理完成
                task_status = query_result.get('header', {}).get('task_status')
                if task_status == '5':
                    audio = query_result.get('payload', {}).get('audio', {}).get('audio')
                    if audio:
                        # base64解码audio，打印下载链接
                        decode_audio = base64.b64decode(audio)
                        audio_url = decode_audio.decode()
                        print("查询任务成功，音频下载链接: %s" % audio_url)
                        return audio_url
                    else:
                        print("查询成功但未获取到音频数据")
                        return None
                else:
                    print("第%s次查询，处理未完成，任务状态码:%s" % (i + 1, task_status))
            else:
                print("查询任务失败，返回状态码: %s" % code)
                return None
        
        # 如果循环结束仍未获取到结果，返回None
        print("查询任务超时，未获取到结果")
        return None
    except Exception as e:
        print(f"查询任务执行异常: {e}")
        return None



def vioceToSpeech(input, num):
    # 1、用户参数，相关参数注意修改
    HOST = ""
    APP_ID = ""
    API_KEY = ""
    API_SECRET = ""

    # 2、执行创建任务
    # file= open("input.txt",encoding='utf-8')
    # text = file.read()
    text=input
    print(text)

    task_id = do_create(text)
    # file.close()

    # 3、执行查询任务
    # 创建任务执行成功后，由返回的task_id执行查询任务
    if task_id:
        query_result = do_query(task_id)
        # 4、下载到本地
        Download_addres = query_result
        if Download_addres:
            f = requests.get(Download_addres)
            # 下载文件，根据需要更改文件后缀
            # 使用当前文件所在目录作为基准，获取项目根目录的绝对路径
            base_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
            # 构建音频文件的相对路径
            filename = os.path.join(base_dir, f"static/audio/temp{num}.mp3")
            
            # 确保目录存在
            os.makedirs(os.path.dirname(filename), exist_ok=True)

            with open(filename, "wb") as code:
                code.write(f.content)
            if filename:
                print("\n音频保存成功！")
    else:
        print("\n创建任务失败，无法生成音频！")
        # 创建一个空白的MP3文件，以避免前端加载失败
        base_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
        filename = os.path.join(base_dir, f"static/audio/temp{num}.mp3")
        os.makedirs(os.path.dirname(filename), exist_ok=True)
        # 创建空文件或复制一个默认的静音MP3文件
        with open(filename, "wb") as code:
            # 如果有一个默认的静音文件，可以复制它
            try:
                default_audio = os.path.join(base_dir, "static/audio/default_silence.mp3")
                if os.path.exists(default_audio):
                    with open(default_audio, "rb") as default:
                        code.write(default.read())
                else:
                    # 创建一个最小的有效MP3文件(静音)
                    code.write(b'\xFF\xFB\x90\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
            except Exception as e:
                print(f"创建默认音频文件失败: {e}")
                # 创建一个空文件
                pass